package com.ycsj.goldmedalnewconcept.cehua;

import android.content.Context;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v4.widget.ViewDragHelper.Callback;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

import com.nineoldandroids.animation.FloatEvaluator;
import com.nineoldandroids.view.ViewHelper;

public class DragLayout extends RelativeLayout implements CloseableLayout {

	// ViewDragHelper的使用步骤：
	// 1 创建ViewDragHelper对象
	// 使用静态的create方法，传入需要帮助处理触摸事件的view，一般是this
	// 2 把触摸事件交给ViewDragHelper去处理
	// onInterceptTouchEvent,调用ViewDragHelper的shouldInterceptTouchEvent
	// onTouchEvent中调用，ViewDragHelper的processTouchEvent
	// 3 决定如何处理，实现callback
	//
	//
	//
	//
	//
	//
	//
	public static enum DragState {
		CLOSE, OPEN, DRAGING;
	}

	public static interface OnDragChangeListener {
		void onStateChanged(DragState state);

		void onDraging(float percent);
	}

	OnDragChangeListener mOnDragChangeListener;

	private ViewDragHelper viewDragHelper;
	float criticalVel;

	public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	public DragLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public DragLayout(Context context) {
		this(context, null);
	}

	public void setOnDragChangeListener(
			OnDragChangeListener mOnDragChangeListener) {
		this.mOnDragChangeListener = mOnDragChangeListener;
	}

	private void init() {
		viewDragHelper = ViewDragHelper.create(this, callBack);

		floatEvaluator = new FloatEvaluator();

		// 1 英寸屏幕的像素数量
		criticalVel = getResources().getDisplayMetrics().density * 160 * 1;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
//		Log.w("一 onInterceptTouchEvent", getMotionEventAction(ev));
		if (viewDragHelper.shouldInterceptTouchEvent(ev)) {
			return true;
		} else {
			return false;
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
//		Log.d("1 onTouchEvent", getMotionEventAction(event));
		viewDragHelper.processTouchEvent(event);

		return true;
	}

	private Callback callBack = new Callback() {

		// ！尝试捕获view
		// child 手指触摸的位置对应的view
		// pointerId 手指的id，主手指是0，后来按下的手指1+
		//
		// 返回值，表示view具备拖拽移动的可能性
		//
		@Override
		public boolean tryCaptureView(View child, int pointerId) {
//			Log.w("二 tryCaptureView", "pointerId:" + pointerId);
			// if(child == mainView){
			// return true;
			// }else if(child == leftView){
			// return false;
			// }
			return pointerId == 0;
		}

		// 当tryCaptureView方法返回true了，此方法会调用
		// capturedChild 被捕获的view
		// activePointerId 手指id
		//
		@Override
		public void onViewCaptured(View capturedChild, int activePointerId) {
//			Log.w("三 onViewCaptured", "activePointerId" + activePointerId);
			super.onViewCaptured(capturedChild, activePointerId);
		}

		// 获得view的水平移动范围
		// 返回正数即可
		@Override
		public int getViewHorizontalDragRange(View child) {
//			Log.d("? getViewHorizontalDragRange", " ");
			
			return 1;
		}

		// 获得view的垂直移动范围
		// 返回正数即可
		@Override
		public int getViewVerticalDragRange(View child) {
//			Log.d("? getViewVerticalDragRange", " ");
			return 1;
		}

		// ! 处理水平方向的移动，限制view的移动范围或添加阻力效果
		// child 被捕获的孩子
		// left 建议值：child的当前的left边 + dx = child的left边的目标值
		// = child.getLeft() + dx
		// dx 移动的触摸事件会导致此方法调用，dx触摸事件在水平方向的移动（两次触摸事件的位置变化）
		// 返回值 child的left边的位置
		//
		@Override
		public int clampViewPositionHorizontal(View child, int left, int dx) {
//			Log.d("2 clampViewPositionHorizontal", "left" + left + "  dx" + dx);

			// return left - dx /2;
			if (child == mainView) {
				if (left >= leftView.getWidth()) {
					left = leftView.getWidth();
				} else if (left <= 0) {
					left = 0;
				}
			}
			if(dx>0){
				return 0;
			}
			
			
			
//			 if (child == leftView) {
//			 if (left >= 0) {
//			 left = 0;
//			 } else if (left <= -leftView.getWidth()) {
//			 left = -leftView.getWidth();
//			 }
//			 }

			return left;
		}

		// ! 与clampViewPositionHorizontal类似，但是top边
		@Override
		public int clampViewPositionVertical(View child, int top, int dy) {
//			Log.d("2 clampViewPositionVertical", "top" + top + " dy" + dy);
			return top - dy;
		}

		// ！在
		// clampViewPositionHorizontal，clampViewPositionVertical方法调用之后
		// ，ViewDragHelper会移动view的位置
		// 移动之后会调用此方法，表示view的位置发生变化了
		// 一般在这里处理动画效果
		// changedView 位置发生变化的View
		// left changedView的当前left边的位置，相当于clampViewPositionHorizontal的返回值
		// top changedView的当前top边的位置，相当于clampViewPositionVertical的返回值
		// dx 表示view的水平位置的变化，！不是触摸点的位置变化
		// dy 表示view的垂直位置的变化，！不是触摸点的位置变化
		//
		@Override
		public void onViewPositionChanged(View changedView, int left, int top,
				int dx, int dy) {
//			Log.d("3 onViewPositionChanged", "left" + left + "  dx" + dx);

			// 当菜单的位置发生变化时，让主界面的位置也发生一致的变化
			if (changedView == leftView) {
				// 保证 菜单界面不动,目的是：维护变量唯一（mainView的left边）
				leftView.offsetLeftAndRight(-dx);
				// 判断 主界面的位置，是否超出范围，
				int tmpMainLeft = mainView.getLeft() + dx;
				if (tmpMainLeft >= leftView.getWidth()) {
					tmpMainLeft = leftView.getWidth();
				} else if (tmpMainLeft <= 0) {
					tmpMainLeft = 0;
				}
				// 菜单界面移动，主界面动
				mainView.offsetLeftAndRight(tmpMainLeft - mainView.getLeft());
			
				// 相当于
				// mainView.layout(mainView.getLeft() + dx, mainView.getTop(),
				// mainView.getRight() + dx, mainView.getBottom());
			}
			// 版本兼容： 判断如果运行此程序的api低于3.0，就重绘
			if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
				invalidate();
			}

			// 根据打开的百分比，进行动画效果
			// 百分比，如果主界面的left边为0就是0，主界面的left边为leftView.getWidth就是1
			float percent = 1.0f * mainView.getLeft() / leftView.getWidth();
			dispatchAnimation(percent);

			updateState(DragState.DRAGING);
			if (mOnDragChangeListener != null) {
				mOnDragChangeListener.onDraging(percent);
			}
		}

		// ! 当手指离开屏幕了，原来被手指捕获的view就被释放了，就会调用此方法
		// 让view归位
		// releasedChild 原先被捕获的view，现在是被释放的view
		// xvel 手指离开屏幕时的水平方向速度，单位是像素/秒
		// yvel 手指离开屏幕时的垂直方向速度，单位是像素/秒
		@Override
		public void onViewReleased(View releasedChild, float xvel, float yvel) {
//			Log.w("五 onViewReleased", "xvel " + xvel + " yvel" + yvel);
			// 先判断速度，再判断mainView的left边的位置，
			// 求出临界速度
			if (xvel > criticalVel) { // 从左向右.打开菜单
//				open();
//				close();
				
			} else if (xvel < -criticalVel) {// 从右向左.关闭菜单
				close();
			} else {
				if (mainView.getLeft() < leftView.getWidth() / 2) { // left边偏向与左侧，关闭菜单
					close();
				} 
				else {// 打开菜单
					open();
//					close();
				}
			}
		}

		// 当拖拽状态发生变化时会调用此方法
		// state 拖拽状态 ： 空闲，正在被拖拽，自动化
		@Override
		public void onViewDragStateChanged(int state) {
//			Log.w("四 六onViewDragStateChanged", getDragState(state));
			// 如果状态是空闲了，那么就停下来了，意味着，mainView的left边要么是0 ，要么是leftWidth。
			if (state == ViewDragHelper.STATE_IDLE) {
				if (mainView.getLeft() == 0) {
					updateState(DragState.CLOSE);
				}
				else if (mainView.getLeft() == leftView.getWidth()) {
					updateState(DragState.OPEN);
				} 
				else {
					updateState(DragState.DRAGING);
				}
			}

			super.onViewDragStateChanged(state);
		}

		// 下面3个方法与边缘触碰有关，不学习
		@Override
		public void onEdgeTouched(int edgeFlags, int pointerId) {
			super.onEdgeTouched(edgeFlags, pointerId);
		}

		@Override
		public boolean onEdgeLock(int edgeFlags) {
			return super.onEdgeLock(edgeFlags);
		}

		@Override
		public void onEdgeDragStarted(int edgeFlags, int pointerId) {
			super.onEdgeDragStarted(edgeFlags, pointerId);
		}

		// 这个方法不需要重写，在遍历寻找触摸的view时会调用此方法
		@Override
		public int getOrderedChildIndex(int index) {
			return super.getOrderedChildIndex(index);
		}

	};
	DragState currentState = DragState.CLOSE;

	private void updateState(DragState state) {
		if (currentState == state) {
			return;
		}

		currentState = state;
		if (mOnDragChangeListener != null) {
			mOnDragChangeListener.onStateChanged(state);
		}
	}

	private View mainView;
	private View leftView;
	private FloatEvaluator floatEvaluator;

	// 在解析xml时，遇到了结束标签，会调用此方法
	protected void onFinishInflate() {
		// 在填充完成之后，可以获得所有的孩子
		// 把角标为0的孩子，主界面对应的布局，提到前面

		mainView = getChildAt(0);
		leftView = getChildAt(1);

		mainView.bringToFront();
		// 等价于
		// bringChildToFront(mainView);
	};

	public void open() {
		// 判断view是否在目标位置，如果不在返回true
		if (viewDragHelper.smoothSlideViewTo(mainView, leftView.getWidth(), 0)) {
			// 和invalidate
			// postInvalidateOnAnimation 下一帧 60分之一秒后，重绘
			// ViewCompat 是support-v4中的兼容类，
			// 为什么重绘的是this呢，也就是DragLayout,因为只有父控件才能知道孩子摆放到那里
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}

	@Override
	public void close() {
		if (viewDragHelper.smoothSlideViewTo(mainView, 0, 0)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}

	@Override
	public void computeScroll() {
		// 返回true，表示经过一小段移动还没有到达指定的位置
		// 参数传true是文档中规定的
		if (viewDragHelper.continueSettling(true)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}

	private static final float SCALE_MAIN_MIN = 1f;
	private static final float SCALE_LEFT_MIN = 1f;

	protected void dispatchAnimation(float percent) {

		// 主界面
		// 缩小 1 -- 》0.5
		float mainScale = floatEvaluator.evaluate(percent, 1, SCALE_MAIN_MIN);
		// 先设置缩放点，再缩放
		// mainView.setPivotX(0);
		// mainView.setPivotY(0.5f * mainView.getHeight());
		// mainView.setScaleX(mainScale);
		// mainView.setScaleY(mainScale);

		ViewHelper.setPivotX(mainView, 0);
		ViewHelper.setPivotY(mainView, mainView.getHeight());
		ViewHelper.setScaleX(mainView, mainScale);
		ViewHelper.setScaleY(mainView, mainScale);

		// 菜单界面
		// 放大
		float leftScale = floatEvaluator.evaluate(percent, SCALE_LEFT_MIN, 1);
		// leftView.setScaleX(leftScale);
		// leftView.setScaleY(leftScale);
		ViewHelper.setScaleX(leftView, leftScale);
		ViewHelper.setScaleY(leftView, leftScale);
		// 平移
		float translationX = floatEvaluator.evaluate(percent,
				-leftView.getWidth() / 2, 0);
		// leftView.setTranslationX(translationX);
		ViewHelper.setTranslationX(leftView, translationX);
		// 透明度
		// leftView.setAlpha(percent);
		ViewHelper.setAlpha(leftView, percent);
	}

	@Override
	public boolean isClose() {
		return currentState == DragState.CLOSE;
	}

	public static String getMotionEventAction(MotionEvent me) {
		// @formatter:off
		int action = me.getAction();
		return action == MotionEvent.ACTION_DOWN ? "DOWN"
				: action == MotionEvent.ACTION_MOVE ? "MOVE"
						: action == MotionEvent.ACTION_UP ? "UP"
								: action == MotionEvent.ACTION_CANCEL ? "ACTION_CANCEL"
										: action == MotionEvent.ACTION_HOVER_ENTER ? "HOVER_ENTER"
												: action == MotionEvent.ACTION_HOVER_MOVE ? "HOVER_MOVE"
														: action == MotionEvent.ACTION_HOVER_EXIT ? "HOVER_EXIT"
																: action == MotionEvent.ACTION_MASK ? "ACTION_MASK"
																		: action == MotionEvent.ACTION_OUTSIDE ? "OUTSIDE"
																				: action == MotionEvent.ACTION_SCROLL ? "SCROLL "
																						: "OTHER";
		// @formatter:on
	}

	public static String getDragState(int state) {
		// @formatter:off
		return state == ViewDragHelper.STATE_DRAGGING ? "DRAGGING"
				: state == ViewDragHelper.STATE_IDLE ? "IDLE"
						: state == ViewDragHelper.STATE_SETTLING ? "SETTLING"
								: "WRONG";
		// @formatter:on
	}

}
